package bank.server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import bank.Bank;
import bank.InactiveException;
import bank.OverdrawException;
import bank.local.LocalAccount;
import bank.local.LocalBank;
import bank.transport.Answer;
import bank.transport.Request;

public class BankHandler implements Runnable {
	// client socket
	private ServerSocket socket;
	// streams
	private ObjectOutputStream out;
	private ObjectInputStream in;
	// bank of the server
	private LocalBank bank;

	/**
	 * Constructor.
	 * 
	 * @param bank The local bank used by the server.
	 * @param socket The socket to the client.
	 */
	public BankHandler(LocalBank bank, ServerSocket socket) {
		this.bank = bank;
		this.socket = socket;
	}

	public void run() {
		while(true) {
			Socket client = null;

			try {
				client = socket.accept();
				
				in = new ObjectInputStream(client.getInputStream());
				out = new ObjectOutputStream(client.getOutputStream());
				
				while(true){				
					Request r = (Request)in.readObject();

					Answer a = action(r);
					
					out.writeObject(a);	
					out.flush();
				}
						
			} catch (IOException e) {
			} catch (ClassNotFoundException e) {
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (InactiveException e) {
				e.printStackTrace();
			} catch (OverdrawException e) {
				e.printStackTrace();
			}
		}
	}


	// Take a request and do correponding action
	private Answer action(Request r) throws IOException, IllegalArgumentException, InactiveException, OverdrawException {
		if (r.str1 == "createAccount") {
			return new Answer(bank.createAccount(r.str2));
		} else if (r.str1 == "removeAccount"){
			return new Answer(bank.removeAccount(r.str2));
		} else if (r.str1 == "getAccountNumbers"){
			return new Answer((String[])bank.getAccountNumbers().toArray());
		} else if (r.str1 == "getAccount"){
			return new Answer(bank.getAccount(r.str2));
		} else if (r.str1 == "transfer"){
			bank.transfer(r.acc1, r.acc2, r.dbl1);
		} else if (r.str1 == "deposit"){
			bank.getAccount(r.str2).deposit(r.dbl1);
		} else if (r.str1 == "withdraw"){
			bank.getAccount(r.str2).withdraw(r.dbl1);
		}
//			Request.CreateAccount c = (Request.CreateAccount) request;
//
//			return new Answer.CreatedAccount(bank.createAccount(c.getOwner()));
//		} else if (request instanceof Request.GetOwner) {
//			Request.GetOwner g = (Request.GetOwner) request;
//
//			return new Answer.GotOwner(bank.getAccount(g.getNumber()).getOwner());
//		} else if (request instanceof Request.GetAccountNumbers) {
//			Set<String> set = bank.getAccountNumbers();
//
//			return new Answer.AccountNumbers(set.toArray());
//		} else if (request instanceof Request.RemoveAccount) {
//			Request.RemoveAccount r = (Request.RemoveAccount) request;
//
//			return new Answer.RemovedAccount(bank.removeAccount(r.getNumber()));
//		} else if (request instanceof Request.Transfer) {
//			Request.Transfer t = (Request.Transfer) request;
//
//			Account a = bank.getAccount(t.getNumberA());
//			Account b = bank.getAccount(t.getNumberB());
//
//			try {
//				bank.transfer(a, b, t.getAmount());
//				return new Answer.TransferStatus(null);
//			} catch (IllegalArgumentException e) {
//				return new Answer.TransferStatus(e);
//			} catch (OverdrawException e) {
//				return new Answer.TransferStatus(e);
//			} catch (InactiveException e) {
//				return new Answer.TransferStatus(e);
//			} catch (Exception e) {
//				return new Answer.DepositStatus(e);
//			}
//		} else if (request instanceof Request.Deposit) {
//			Request.Deposit d = (Request.Deposit) request;
//
//			Account a = bank.getAccount(d.getNumber());
//
//			try {
//				a.deposit(d.getAmount());
//				return new Answer.DepositStatus(null);
//			} catch (IllegalArgumentException e) {
//				return new Answer.DepositStatus(e);
//			} catch (InactiveException e) {
//				return new Answer.DepositStatus(e);
//			} catch (Exception e) {
//				return new Answer.DepositStatus(e);
//			}
//		} else if (request instanceof Request.Withdraw) {
//			Request.Withdraw d = (Request.Withdraw) request;
//
//			Account a = bank.getAccount(d.getNumber());
//
//			try {
//				a.withdraw(d.getAmount());
//				return new Answer.WithdrawStatus(null);
//			} catch (IllegalArgumentException e) {
//				return new Answer.WithdrawStatus(e);
//			} catch (InactiveException e) {
//				return new Answer.WithdrawStatus(e);
//			} catch (OverdrawException e) {
//				return new Answer.WithdrawStatus(e);
//			} catch (Exception e) {
//				return new Answer.DepositStatus(e);
//			}
//		} else if (request instanceof Request.GetBalance) {
//			Request.GetBalance g = (Request.GetBalance) request;
//
//			Account a = bank.getAccount(g.getNumber());
//
//			return new Answer.GotBalance(a.getBalance());
//		} else if (request instanceof Request.IsActive) {
//			Request.IsActive i = (Request.IsActive) request;
//
//			Account a = bank.getAccount(i.getNumber());
//
//			return new Answer.IsActive(a.isActive());
//		}
		return null;
	}
}
